﻿using System.Windows;
using System.Windows.Controls;
using System.Xml;
using System.Xml.Linq;
using System.Collections.Generic;
using System;

namespace DynamicGeometry
{
    public interface ILinearFigure : IFigure
    {
        double GetNearestParameterFromPoint(Point point);
        Point GetPointFromParameter(double parameter);
        Tuple<double, double> GetParameterDomain();
    }

    public static class ILinearFigureExtensions
    {
        public static Point SnapPointToFigure(this ILinearFigure figure, Point point)
        {
            var parameter = figure.GetNearestParameterFromPoint(point);
            return figure.GetPointFromParameter(parameter);
        }

        public static bool IsPointWithinTolerance(this ILinearFigure figure, Point point)
        {
            Point pointOnFigure = figure.SnapPointToFigure(point);
            return Math.Abs(pointOnFigure.Distance(point)) < figure.Drawing.CoordinateSystem.CursorTolerance;
        }
    }

    public interface IFigure : IEquatable<IFigure>
    {
        Drawing Drawing { get; set; }

        IEnumerable<IFigure> Dependencies { get; set; }
        IFigureList Dependents { get; }

        string Name     { get; set; }

        string c_store_id { get; set; }

        string c_guid { get; set; }

        string c_type { get; set; }

        bool c_is_modify { get; set; }

        bool Exists     { get; set; }
        bool Selected   { get; set; }
        void UpdateExistence();
        void Recalculate();
        void UpdateVisual();
        
        /// <summary>
        /// Determines if a point lies on a figure and returns the figure in this case.
        /// </summary>
        /// <param name="point">Point's logical coordinates</param>
        /// <returns>A figure (usually itself or a child) if a point is on this figure, null otherwise</returns>
        IFigure HitTest(Point point);
        
        void OnAddingToCanvas(Canvas newContainer);
        void OnRemovingFromCanvas(Canvas leavingContainer);
        
        int ZIndex { get; set; }
        bool Visible { get; set; }
        
        void WriteXml(XmlWriter writer);
        void ReadXml(XElement element);
    }
}